/*
 * Copyright 2012 Alan Burlison, alan@bleaklow.com.  All rights reserved.
 * Use is subject to license terms.  See LICENSE.txt for details.
 */

#ifndef trace_h
#define	trace_h

// NOTE: Also need to #define TASK_TRACE on the gcc command-line
// to instrument all the library ISRs.

// Tracing pins and ports - modify as required.
#define TRACE_CAN_RUN_DDR  DDRB         // Duemilanove pin D8
#define TRACE_CAN_RUN_PORT PORTB
#define TRACE_CAN_RUN_PIN  PORTB0
#define TRACE_RUN_DDR      DDRB         // Duemilanove pin D9
#define TRACE_RUN_PORT     PORTB
#define TRACE_RUN_PIN      PORTB1
#define TRACE_ISR_DDR      DDRC         // Duemilanove pin A2 / D16
#define TRACE_ISR_PORT     PORTC
#define TRACE_ISR_PIN      PORTC2

// Redefine the ISR macro to toggle the TRACE_ISR pin before/after each ISR
// body.  Also saves *all* registers and uses a RCALL to call the real ISR and
// will therefore be slower than the uninstrumented ISR as a result.
#undef ISR
#define ISR_VECTOR_BODY(V) \
  SET_BIT_HI(TRACE_ISR_PORT, TRACE_ISR_PIN); \
  asm("push r1\n" \
      "push r0\n" \
      "in r0,__SREG__\n" \
      "push r0\n" \
      "clr __zero_reg__\n" \
      "push r18\n" \
      "push r19\n" \
      "push r20\n" \
      "push r21\n" \
      "push r22\n" \
      "push r23\n" \
      "push r24\n" \
      "push r25\n" \
      "push r26\n" \
      "push r27\n" \
      "push r30\n" \
      "push r31\n" \
  ); \
  V(); \
  asm("pop r31\n" \
      "pop r30\n" \
      "pop r27\n" \
      "pop r26\n" \
      "pop r25\n" \
      "pop r24\n" \
      "pop r23\n" \
      "pop r22\n" \
      "pop r21\n" \
      "pop r20\n" \
      "pop r19\n" \
      "pop r18\n" \
      "pop r0\n" \
      "out __SREG__,r0\n" \
      "pop r0\n" \
      "pop r1\n" \
  ); \
  SET_BIT_LO(TRACE_ISR_PORT, TRACE_ISR_PIN); \
  reti()
#ifdef __cplusplus
#define ISR(V, ...) \
  extern "C" void V(void) __attribute__ ((signal, __INTR_ATTRS)) ISR_NAKED __VA_ARGS__; \
  extern "C" void V ## _inner(void); \
  void V(void) { ISR_VECTOR_BODY(V ## _inner); } \
  void V ## _inner(void)
#else
#define ISR(V, ...) \
  extern void V(void) __attribute__ ((signal, __INTR_ATTRS)) ISR_NAKED __VA_ARGS__; \
  extern void V ## _inner(void); \
  void V(void) { ISR_VECTOR_BODY(V ## _inner); } \
  void V ## _inner(void)
#endif

#endif	/* trace_h */

